﻿
namespace HSS.Xaml.UI.Controls
{
	#region Using Directives
	using System.Windows;
	using System.Windows.Controls;
	using System.Windows.Input;
	using System.Windows.Media;

	#endregion

	#region PropertyGridHeader
	/// <summary>
	/// PropertyGridHeader is a GridEntry that is the header for each category of properties contained in the Grid
	/// </summary>
	[TemplatePart(Name = PropertyGridHeader.PART_CollapseImage, Type = typeof(Image))]
	[TemplatePart(Name = PropertyGridHeader.PART_ExpandImage, Type = typeof(Image))]
	[TemplatePart(Name = PropertyGridHeader.PART_HeaderLabel, Type = typeof(TextBlock))]

	[TemplateVisualState(GroupName = PropertyGridHeader.STATEGROUP_SelectionStates, Name = PropertyGridHeader.STATE_SelectedActive)]
	[TemplateVisualState(GroupName = PropertyGridHeader.STATEGROUP_SelectionStates, Name = PropertyGridHeader.STATE_SelectedInactive)]
	[TemplateVisualState(GroupName = PropertyGridHeader.STATEGROUP_SelectionStates, Name = PropertyGridHeader.STATE_Unselected)]

	[TemplateVisualState(GroupName = PropertyGridHeader.STATEGROUP_ExpansionStates, Name = PropertyGridHeader.STATE_Expanded)]
	[TemplateVisualState(GroupName = PropertyGridHeader.STATEGROUP_ExpansionStates, Name = PropertyGridHeader.STATE_Collapsed)]
	public sealed class PropertyGridHeader : ContentControl, IPropertyGridHeader
	{
		#region Parts
		/// <summary>
		/// The name of the CollapseImage Part
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "PART")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores")]
		public const string PART_CollapseImage = "CollapseImage";
		/// <summary>
		/// The name of the ExpandImage Part
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "PART")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores")]
		public const string PART_ExpandImage = "ExpandImage";
		/// <summary>
		/// The name of the HeaderLabel Part
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "PART")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores")]
		public const string PART_HeaderLabel = "HeaderLabel";

		/// <summary>
		/// The name of the SelectionStates VisualStateGroup
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "STATEGROUP")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores")]
		public const string STATEGROUP_SelectionStates = "SelectionStates";
		/// <summary>
		/// The name of the SelectedActive State
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "STATE")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores")]
		public const string STATE_SelectedActive = "SelectedActive";
		/// <summary>
		/// The name of the SelectedInactive State
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "STATE")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores")]
		public const string STATE_SelectedInactive = "SelectedInactive";
		/// <summary>
		/// The name of the Unselected State
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "STATE")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores")]
		public const string STATE_Unselected = "Unselected";

		/// <summary>
		/// The name of the ExpansionStates VisualStateGroup
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "STATEGROUP")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores")]
		public const string STATEGROUP_ExpansionStates = "ExpansionStates";
		/// <summary>
		/// The name of the Expanded State
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "STATE")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores")]
		public const string STATE_Expanded = "Expanded";
		/// <summary>
		/// The name of the Collapsed State
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "STATE")]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1707:IdentifiersShouldNotContainUnderscores")]
		public const string STATE_Collapsed = "Collapsed";
		#endregion

		#region Fields
		readonly object key = new object();
		DoubleClickDetection doubleClickDetection;
		bool isRemoved;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructor
		/// </summary>
		public PropertyGridHeader()
		{
			this.doubleClickDetection = new DoubleClickDetection();
			this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(PropertyGridHeader_MouseLeftButtonUp);
			base.DefaultStyleKey = typeof(PropertyGridHeader);
			this.Unloaded += new RoutedEventHandler(PropertyGridHeader_Unloaded);
		}

		void PropertyGridHeader_Unloaded(object sender, RoutedEventArgs e)
		{
			this.Unloaded -= new RoutedEventHandler(PropertyGridHeader_Unloaded);
			this.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(PropertyGridHeader_MouseLeftButtonUp);
			if (null != this._headerLabel)
				this._headerLabel.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(HeaderLabel_MouseLeftButtonUp);
			if (null != this._collapseImage)
				_collapseImage.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(CollapseImage_MouseLeftButtonUp);
			if (null != _expandImage)
				_expandImage.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(ExpandImage_MouseLeftButtonUp);
		}
		#endregion

		#region Properties

		/// <summary>
		/// Gets or sets the PropertyGrid associated with this Item.
		/// </summary>
		internal PropertyGrid PropertyGrid
		{
			get { return _propertyGrid; }
			set { _propertyGrid = value; }
		} PropertyGrid _propertyGrid;

		#region IPropertyGridItem
		/// <summary>
		/// 
		/// </summary>
		public int RowIndex { get; set; }
		/// <summary>
		/// Gets or sets whether this item is selected
		/// </summary>
		public bool IsSelected
		{
			get
			{
				return _isSelected;
			}
			set
			{
				if (_isSelected != value)
				{
					_isSelected = value;

					if (_isSelected)
					{
						if (!this.IsActive)
							this.Focus();
					}
				}
			}
		} bool _isSelected;
		/// <summary>
		/// 
		/// </summary>
		public string Category { get { return HeaderLabelText; } }
		/// <summary>
		/// Gets the DisplayName of this entry
		/// </summary>
		public string DisplayName { get { return HeaderLabelText; } }
		/// <summary>
		/// Gets the Description of this entry
		/// </summary>
		public string Description { get { return string.Empty; } }
		/// <summary>
		/// Is this Entry Visible
		/// </summary>
		public bool IsVisible
		{
			get
			{
				return ((FrameworkElement)this.Parent).Visibility == Visibility.Visible;
			}
			set
			{
				if (null == this.Parent)
					return;
				((FrameworkElement)this.Parent).Visibility = value ? Visibility.Visible : Visibility.Collapsed;
			}
		}
		/// <summary>
		/// Get if this Header has focus
		/// </summary>
		public bool IsActive { get; private set; }
		/// <summary>
		/// Get if this Item is currently editing; not used for a Header Row
		/// </summary>
		public bool IsEditorFocused { get; private set; }
		/// <summary>
		/// Gets or sets the Instance object
		/// </summary>
		public object Instance { get; internal set; }
		#endregion

		#region IsExpanded
		/// <summary>
		/// Gets or sets a value indicating whether the
		/// <see cref="PropertyGridHeader" /> is expanded.
		/// </summary>
		/// <value>
		/// True if the header is expanded; otherwise, false. The
		/// default is true.
		/// </value>
		public bool IsExpanded
		{
			get { return (bool)GetValue(IsExpandedProperty); }
			set { SetValue(IsExpandedProperty, value); }
		}
		/// <summary>
		/// Using a DependencyProperty as the backing store for IsExpanded.  This enables animation, styling, binding, etc...
		/// </summary>
		public static readonly DependencyProperty IsExpandedProperty =
			DependencyProperty.Register(
				"IsExpanded",
				typeof(bool),
				typeof(PropertyGridHeader),
				new PropertyMetadata(true, IsExpandedPropertyChanged));
		private static void IsExpandedPropertyChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
		{
			PropertyGridHeader header = dp as PropertyGridHeader;
			bool isExpanded = (bool)e.NewValue;
			if (isExpanded)
				header.PropertyGrid.ToggleVisibility(true, header.Category);
			else
				header.PropertyGrid.ToggleVisibility(false, header.Category);
			header.UpdateVisualState();
		}
		#endregion

		#region CollapseImage
		/// <summary>
		/// Gets the CollapseImage Control
		/// </summary>
		public Image CollapseImage
		{
			get { return _collapseImage; }
			private set
			{
				if (null != _collapseImage)
					_collapseImage.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(CollapseImage_MouseLeftButtonUp);
				_collapseImage = value;
				if (null != _collapseImage)
					_collapseImage.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(CollapseImage_MouseLeftButtonUp);
			}
		} Image _collapseImage;
		#endregion

		#region CollapseImageSource
		/// <summary>
		/// Gets or sets the Image to display to indicate the header is currently expanded and clicking here will collapse the header
		/// </summary>
		public ImageSource CollapseImageSource
		{
			get { return (ImageSource)GetValue(CollapseImageSourceProperty); }
			set { SetValue(CollapseImageSourceProperty, value); }
		}
		/// <summary>
		/// Using a DependencyProperty as the backing store for CollapseImageSource.  This enables animation, styling, binding, etc...
		/// </summary>
		public static readonly DependencyProperty CollapseImageSourceProperty =
			DependencyProperty.Register("CollapseImageSource", typeof(ImageSource), typeof(PropertyGridHeader), new PropertyMetadata(null));
		#endregion

		#region ExpandImage
		/// <summary>
		/// Gets the ExpandImage Control
		/// </summary>
		public Image ExpandImage
		{
			get { return _expandImage; }
			private set
			{
				if (null != _expandImage)
					_expandImage.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(ExpandImage_MouseLeftButtonUp);
				_expandImage = value;
				if (null != _expandImage)
					_expandImage.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(ExpandImage_MouseLeftButtonUp);
			}
		} Image _expandImage;
		#endregion

		#region ExpandImageSource
		/// <summary>
		/// Gets or sets the Image to display to indicate the header is currently collapsed and clicking here will expand the header
		/// </summary>
		public ImageSource ExpandImageSource
		{
			get { return (ImageSource)GetValue(ExpandImageSourceProperty); }
			set { SetValue(ExpandImageSourceProperty, value); }
		}
		/// <summary>
		/// Using a DependencyProperty as the backing store for ExpandImageSource.  This enables animation, styling, binding, etc...
		/// </summary>
		public static readonly DependencyProperty ExpandImageSourceProperty =
			DependencyProperty.Register("ExpandImageSource", typeof(ImageSource), typeof(PropertyGridHeader), new PropertyMetadata(null));
		#endregion

		#region HeaderLabel
		/// <summary>
		/// Gets the HeaderLabel TextBlock
		/// </summary>
		public TextBlock HeaderLabel
		{
			get { return _headerLabel; }
			private set
			{
				if (null != _headerLabel)
					_headerLabel.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(HeaderLabel_MouseLeftButtonUp);
				_headerLabel = value;
				if (null != _headerLabel)
					_headerLabel.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(HeaderLabel_MouseLeftButtonUp);
			}
		} TextBlock _headerLabel;
		#endregion

		#region HeaderLabelText
		/// <summary>
		/// Gets or sets the Text to display for this label
		/// </summary>
		public string HeaderLabelText
		{
			get { return (string)GetValue(HeaderLabelTextProperty); }
			set { SetValue(HeaderLabelTextProperty, value); }
		}
		/// <summary>
		/// Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
		/// </summary>
		public static readonly DependencyProperty HeaderLabelTextProperty =
			DependencyProperty.Register("HeaderLabelText", typeof(string), typeof(PropertyGridHeader), new PropertyMetadata(string.Empty));
		#endregion

		#endregion

		#region Overrides
		/// <summary>
		/// Apply the control template.
		/// </summary>
		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
			this.IsTabStop = false;
			this.CollapseImage = this.GetTemplateChild(PropertyGridHeader.PART_CollapseImage) as Image;
			this.ExpandImage = this.GetTemplateChild(PropertyGridHeader.PART_ExpandImage) as Image;
			this.HeaderLabel = this.GetTemplateChild(PropertyGridHeader.PART_HeaderLabel) as TextBlock;
			this.UpdateVisualState();
		}
		/// <summary>
		/// Process the Got Focus action.
		/// </summary>
		/// <param name="e">The RoutedEventArgs args.</param>
		protected override void OnGotFocus(RoutedEventArgs e)
		{
			base.OnGotFocus(e);
			this.IsActive = true;
			this.PropertyGrid.SelectItem(this);
		}
		/// <summary>
		/// Process Lost Focus action.
		/// </summary>
		/// <param name="e">The RoutedEventArgs args.</param>
		protected override void OnLostFocus(RoutedEventArgs e)
		{
			base.OnLostFocus(e);
			this.IsActive = false;
			this.UpdateVisualState();
		}
		/// <summary>
		/// Process MouseLeftButtonDown action.
		/// </summary>
		/// <param name="e">The MouseButtonEventArgs args.</param>
		protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
		{
			base.OnMouseLeftButtonDown(e);
			this.IsTabStop = true;
			this.Focus();
		}
		/// <summary>
		/// Process the KeyDown action.
		/// </summary>
		/// <param name="e">The <see cref="KeyEventArgs"/> args.</param>
		protected override void OnKeyDown(KeyEventArgs e)
		{
			Guard.ArgumentNotNull(e, "e");
			if (Keyboard.Modifiers == ModifierKeys.None)
			{
				switch (e.Key)
				{
					case System.Windows.Input.Key.Tab:
						e.Handled = true;
						return;
				}
			}
			base.OnKeyDown(e);
		}
		#endregion

		#region Methods
		/// <summary>
		/// Select this item
		/// </summary>
		public void Select()
		{
			this.IsSelected = true;
			this.UpdateVisualState();
		}
		/// <summary>
		/// Select this item, activate the Editor and Execute the default action for the Editor
		/// </summary>
		public void ExecuteDefaultAction()
		{
		}
		/// <summary>
		/// Deselect this item
		/// </summary>
		public void Deselect()
		{
			this.IsSelected = false;
			this.IsTabStop = false;
			this.UpdateVisualState();
		}
		/// <summary>
		/// Activate this item
		/// </summary>
		/// <returns></returns>
		public void Activate()
		{
			this.IsTabStop = true;
			if (!this.IsActive)
				this.Focus();
		}
		/// <summary>
		/// Refresh from the current value.
		/// </summary>
		public void Refresh()
		{

		}
		/// <summary>
		/// Clean up instance state
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
		public void OnRemoved()
		{
			if (this.isRemoved)
				return;
			this.isRemoved = true;
			try
			{
				this.Deselect();
			}
			catch { }
			try
			{
				this.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(PropertyGridHeader_MouseLeftButtonUp);
			}
			catch { }
		}
		/// <summary>
		/// 
		/// </summary>
		private void UpdateVisualState()
		{
			if (this.IsExpanded)
				VisualStateManager.GoToState(this, STATE_Expanded, false);
			else
				VisualStateManager.GoToState(this, STATE_Collapsed, false);

			if (this.IsSelected)
			{
				if (this.IsActive)
					VisualStateManager.GoToState(this, STATE_SelectedActive, false);
				else
					VisualStateManager.GoToState(this, STATE_SelectedInactive, false);
			}
			else
				VisualStateManager.GoToState(this, STATE_Unselected, false);
		}
		#endregion

		#region EventHandlers
		void PropertyGridHeader_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			this.Focus();
		}
		void HeaderLabel_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			if (this.doubleClickDetection.ProcessClick(key))
				this.IsExpanded = !this.IsExpanded;
		}
		void CollapseImage_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			this.IsExpanded = false;
		}
		void ExpandImage_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			this.IsExpanded = true;
		}
		#endregion
	}
	#endregion
}
